<template>
  <a-cascader
    v-bind="attrs"
    :value="cascaderValue"
    :options="options"
    :disabled="disabled"
    :placeholder="placeholder"
    :loading="loading"
    allow-clear
    @change="handleChange"
  />
</template>

<script setup lang="ts">
  import { ref, onMounted, watch } from 'vue';
  import { message } from 'ant-design-vue';
  import { useAttrs } from '/@/hooks/core/useAttrs';
  import { listByDepthApi } from './api';

  interface CascaderOption {
    value: string;
    label: string;
    children?: CascaderOption[];
  }

  interface AreaMeta {
    depth: number;
    provinceCode?: string;
    cityCode?: string;
  }

  const props = defineProps({
    value: {
      type: [Array, String],
      default: () => [],
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    placeholder: {
      type: String,
      default: '请选择省市区',
    },
  });

  const emit = defineEmits(['update:value', 'change']);
  const attrs = useAttrs();

  const cascaderValue = ref<string[]>([]);
  const pendingValue = ref<string | string[] | null>(null);
  const options = ref<CascaderOption[]>([]);
  const areaMeta = ref<Map<string, AreaMeta>>(new Map());
  const loading = ref(false);

  function unwrapResponse(res: any) {
    if (Array.isArray(res)) {
      return res;
    }
    if (Array.isArray(res?.result)) {
      return res.result;
    }
    if (Array.isArray(res?.data)) {
      return res.data;
    }
    return [];
  }

  function normalizeRawValue(val: any): string | string[] | null {
    if (val === undefined || val === null) {
      return null;
    }
    if (Array.isArray(val)) {
      return val;
    }
    if (typeof val === 'string') {
      const arr = val
        .split(',')
        .map((item) => item.trim())
        .filter(Boolean);
      if (arr.length > 1) {
        return arr;
      }
      if (arr.length === 1) {
        return arr[0];
      }
      return null;
    }
    return null;
  }

  function buildPathFromCode(code: string): string[] {
    const meta = areaMeta.value.get(code);
    if (!meta) {
      return [];
    }
    if (meta.depth === 4) {
      return [meta.provinceCode!, meta.cityCode!, code];
    }
    if (meta.depth === 3) {
      return [meta.provinceCode!, code];
    }
    if (meta.depth === 2) {
      return [code];
    }
    return [];
  }

  function applyPendingValue() {
    const raw = pendingValue.value;
    if (!raw) {
      cascaderValue.value = [];
      return;
    }
    if (Array.isArray(raw)) {
      cascaderValue.value = raw;
      return;
    }
    if (areaMeta.value.size) {
      cascaderValue.value = buildPathFromCode(raw);
    }
  }

  async function fetchByDepth(depth: number) {
    const res = await listByDepthApi({ depth });
    return unwrapResponse(res);
  }

  function buildAreaTree(provinces: any[], cities: any[], regions: any[]) {
    areaMeta.value.clear();
    const provinceMap = new Map<string, CascaderOption>();
    const cityMap = new Map<string, CascaderOption>();

    provinces.forEach((item) => {
      const code = item?.provinceCode;
      const name = item?.provinceName;
      if (!code || !name) {
        return;
      }
      const node: CascaderOption = {
        value: code,
        label: name,
        children: [],
      };
      provinceMap.set(code, node);
      areaMeta.value.set(code, { depth: 2 });
    });

    cities.forEach((item) => {
      const code = item?.cityCode;
      const name = item?.cityName;
      const provinceCode = item?.provinceCode;
      if (!code || !name || !provinceCode) {
        return;
      }
      const provinceNode = provinceMap.get(provinceCode);
      if (!provinceNode) {
        return;
      }
      const node: CascaderOption = {
        value: code,
        label: name,
        children: [],
      };
      provinceNode.children?.push(node);
      cityMap.set(code, node);
      areaMeta.value.set(code, { depth: 3, provinceCode });
    });

    regions.forEach((item) => {
      const code = item?.regionCode;
      const name = item?.regionName;
      const cityCode = item?.cityCode;
      const provinceCode = item?.provinceCode || areaMeta.value.get(item?.cityCode)?.provinceCode;
      if (!code || !name || !cityCode) {
        return;
      }
      const cityNode = cityMap.get(cityCode);
      if (!cityNode) {
        return;
      }
      if (!cityNode.children) {
        cityNode.children = [];
      }
      cityNode.children.push({
        value: code,
        label: name,
      });
      areaMeta.value.set(code, {
        depth: 4,
        provinceCode,
        cityCode,
      });
    });

    const tree = Array.from(provinceMap.values());
    tree.forEach((province) => {
      if (!province.children?.length) {
        delete province.children;
      } else {
        province.children.forEach((city) => {
          if (!city.children?.length) {
            delete city.children;
          }
        });
      }
    });

    return tree;
  }

  async function loadAreaOptions() {
    loading.value = true;
    try {
      const [provinceList, cityList, regionList] = await Promise.all([fetchByDepth(2), fetchByDepth(3), fetchByDepth(4)]);
      options.value = buildAreaTree(provinceList, cityList, regionList);
      applyPendingValue();
    } catch (error) {
      console.error('加载省市区失败', error);
      message.error('加载省市区失败');
    } finally {
      loading.value = false;
    }
  }

  function handleChange(value: string[]) {
    cascaderValue.value = value;
    const latestCode = value?.length ? value[value.length - 1] : '';
    emit('update:value', latestCode);
    emit('change', value);
  }

  watch(
    () => props.value,
    (val) => {
      pendingValue.value = normalizeRawValue(val);
      applyPendingValue();
    },
    { immediate: true }
  );

  onMounted(() => {
    loadAreaOptions();
  });
</script>
